package com.lagou.homework.config;

import com.alibaba.druid.pool.DruidDataSource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.retry.RetryNTimes;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;

@Slf4j
@Configuration
public class DatasourceConfig {

    /** 数据源配置对象 */
    public DataSourceProperties dataSourceProperties;

    /** 数据连接池 */
    private DruidDataSource druidDataSource;

    /**
     * 初始化连接池信息并且监听zookeeper
     *
     * @param zookeeperProperties zookeeper 连接信息
     * @return 数据连接池
     */
    @SneakyThrows
    @Bean
    public DataSource init(ZookeeperProperties zookeeperProperties) {
        final String CONFIG_PREFIX = zookeeperProperties.getDataSourceRoot();
        dataSourceProperties = new DataSourceProperties();
        CuratorFramework client = CuratorFrameworkFactory.newClient(zookeeperProperties.getConnectString(), new RetryNTimes(3, 10000));
        client.start();
        List<String> childrenNames = client.getChildren().forPath(CONFIG_PREFIX);
        for (String childrenName : childrenNames) {
            String value = new String(client.getData().forPath(CONFIG_PREFIX + "/" + childrenName));
            switch (childrenName){
                case "url": dataSourceProperties.setUrl(value); break;
                case "username": dataSourceProperties.setUsername(value); break;
                case "password": dataSourceProperties.setPassword(value); break;
                case "driverClassName": dataSourceProperties.setDriverClassName(value); break;
                default: log.warn("未知参数！！");
            }
        }
        PathChildrenCache watcher = new PathChildrenCache(client, CONFIG_PREFIX, true);
        watcher.getListenable().addListener((curatorFramework, event)->{
            String path = event.getData().getPath();
            if (path.startsWith(CONFIG_PREFIX)) {
                String key = path.replace(CONFIG_PREFIX + "/", "");
                switch (key) {
                    case "url": dataSourceProperties.setUrl(new String(event.getData().getData())); break;
                    case "username": dataSourceProperties.setUsername(new String(event.getData().getData())); break;
                    case "password": dataSourceProperties.setPassword(new String(event.getData().getData())); break;
                    case "driverClassName": dataSourceProperties.setDriverClassName(new String(event.getData().getData())); break;
                    default: log.warn("未知参数！！");
                }
                resetDataSource();
            }
        });

        watcher.start(PathChildrenCache.StartMode.BUILD_INITIAL_CACHE);
        return create();
    }

    /**
     * 重置连接池信息
     */
    public void resetDataSource() {
        if (druidDataSource == null) {
            throw new NullPointerException("数据源为空，无法重置！！");
        }
        try {
            druidDataSource.restart();
            druidDataSource.setUsername(dataSourceProperties.getUsername());
            druidDataSource.setUrl(dataSourceProperties.getUrl());
            druidDataSource.setPassword(dataSourceProperties.getPassword());
            druidDataSource.init();
            log.info("数据源配置更新");
        } catch (Exception e) {
            log.error("更新数据源失败！！！");
        }
    }

    /**
     * 创建数据连接池
     *
     * @return 返回数据连接池
     */
    public DataSource create(){
        druidDataSource = DataSourceBuilder.create()
                .driverClassName(druidDataSource.getDriverClassName())
                .type(DruidDataSource.class)
                .url(this.dataSourceProperties.getUrl())
                .username(this.dataSourceProperties.getUsername())
                .password(this.dataSourceProperties.getPassword())
                .build();
        druidDataSource.setMinIdle(10);
        druidDataSource.setMaxActive(1000);
        druidDataSource.setKeepAlive(true);
        druidDataSource.setInitialSize(10);
        return druidDataSource;
    }

    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource) throws SQLException {
        return new JdbcTemplate(dataSource);
    }

}
